﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Threading;
using System.Windows.Threading;
using Shoozla.DataModel;
using Shoozla.View;
using System.Collections.Generic;
using System.Linq;

namespace Shoozla.ViewModel
{
    /// <summary>
    /// Base class for all ViewModel classes in the application.
    /// It provides support for property change notifications 
    /// and has a DisplayName property.  This class is abstract.
    /// </summary>
    public abstract class ViewModelBase : INotifyPropertyChanged, IDisposable
    {
        private static bool? _isInDesignMode;
        protected Dispatcher _dispatcherUIThread;
        public MultithreadingObservableCollection<Mp3File> CurrentItems { get; set; } //item displayed     

        UserControl _currentView = null;
        public UserControl CurrentView
        {
            get { return _currentView; }
            set
            {
                if (_currentView != value)
                {
                    _currentView = value;
                    OnPropertyChanged("CurrentView");
                }
            }
        }

        public StatisticsLogger Logger
        {
            get { return App.Logger; }
            set { App.Logger = value; }
        }



        #region Properties

        //private MultithreadingObservableCollection<Mp3File> _allItems;
        //public MultithreadingObservableCollection<Mp3File> App.AllItems
        //{
        //    get
        //    {
        //        return _allItems;
        //    }
        //    set
        //    {
        //        if (value != _allItems && value != null)
        //        {
        //            _allItems = value;
        //            _allItems.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(list_CollectionChanged);
        //            OnPropertyChanged("App.AllItems");
        //            OnPropertyChanged("Mp3WithCovers");
        //        }

        //    }
        //}

        //private MultithreadingObservableCollection<Mp3File> _currentItems;
        //public MultithreadingObservableCollection<Mp3File> CurrentItems
        //{
        //    get
        //    {
        //        if (_currentItems == null)
        //            return App.AllItems;
        //        return _currentItems;
        //    }
        //    set
        //    {
        //        if (value != _currentItems && value != null)
        //        {
        //            _currentItems = value;
        //            _currentItems.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(list_CollectionChanged);
        //            OnPropertyChanged("CurrentItems");
        //        }

        //    }
        //}

        public MultithreadingObservableCollection<Mp3File> SelectedItems
        {
            get
            {              
                MultithreadingObservableCollection<Mp3File> list;
                lock (this)
                {
                    //get all selected items (binding on IsSelected property)
                    List<Mp3File> selected = (
                        from m in App.AllItems
                        where m.IsSelected == true
                        select m).ToList<Mp3File>();


                    Mp3File[] a = selected.ToArray();
                    list = new MultithreadingObservableCollection<Mp3File>(a, _dispatcherUIThread);
                }
                return list;
            }
        }

        public int Mp3WithCovers
        {
            get
            {
                var covers = (from c in App.AllItems
                              where c.HasCover == true
                              select c);
                return covers.Count();
            }
        }

        void list_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            //OnPropertyChanged("AllItems");
            OnPropertyChanged("CurrentItems");
            OnPropertyChanged("Mp3WithCovers");
        }

        #endregion

        #region Do Commands

        protected void DoCmdSelectAll()
        {
            foreach (Mp3File m in CurrentItems)
                m.IsSelected = true;
        }

        protected void DoCmdSelectNone()
        {
            foreach (Mp3File m in CurrentItems)
                m.IsSelected = false;
        }

        #endregion

        #region Commands
        private RelayCommand _CmdSelectAll;
        public RelayCommand CmdSelectAll
        {
            get
            {
                if (_CmdSelectAll == null)
                {
                    _CmdSelectAll = new RelayCommand(param => DoCmdSelectAll(), param => CanExecuteCurrentItemsOp());
                }
                return _CmdSelectAll;
            }
        }

        private RelayCommand _CmdSelectNone;
        public RelayCommand CmdSelectNone
        {
            get
            {
                if (_CmdSelectNone == null)
                {
                    _CmdSelectNone = new RelayCommand(param => DoCmdSelectNone(), param => CanExecuteCurrentItemsOp());
                }
                return _CmdSelectNone;
            }
        }

        protected bool CanExecuteItemsOp()
        {
            if (App.AllItems.Count > 0)
                return true;
            else
                return false;
        }

        protected bool CanExecuteCurrentItemsOp()
        {
            if (CurrentItems.Count > 0)
                return true;
            else
                return false;
        }

        protected bool CanExecuteSelectedItemsOp()
        {
            if (SelectedItems.Count > 0)
                return true;
            else
                return false;
        }

        #endregion

        #region events

        public event EventHandler ItemRead;
      
        public event CoverSavedHandler FileSaved;
        public event ItemOperationStartedHandler ItemOperationStarted;
        public event EventHandler ItemOperationFinished;
        public delegate void ItemOperationStartedHandler(int num,string action);
        public delegate void CoverSavedHandler(string filename);



        #endregion

        #region Constructor

        protected ViewModelBase()
        {
            _dispatcherUIThread = Dispatcher.CurrentDispatcher;
            CurrentItems = new MultithreadingObservableCollection<Mp3File>(_dispatcherUIThread);
            CurrentItems.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(list_CollectionChanged);
        }

        public ViewModelBase(Dispatcher dispatcher)
        {
            _dispatcherUIThread = dispatcher;
            CurrentItems = new MultithreadingObservableCollection<Mp3File>(_dispatcherUIThread);
            CurrentItems.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(list_CollectionChanged);
        }

        protected virtual bool CanExecuteUI()
        {
            switch(App.CurrentAppStatus)
            {
                case App.AppStatus.Idle: { return true; }
                default: { return false; }
            }
        }

        #endregion // Constructor

        #region DisplayName

        /// <summary>
        /// Returns the user-friendly name of this object.
        /// Child classes can set this property to a new value,
        /// or override it to determine the value on-demand.
        /// </summary>
        public virtual string DisplayName { get; protected set; }

        #endregion // DisplayName

        #region Debugging Aides

        /// <summary>
        /// Warns the developer if this object does not have
        /// a public property with the specified name. This 
        /// method does not exist in a Release build.
        /// </summary>
        [Conditional("DEBUG")]
        [DebuggerStepThrough]
        public void VerifyPropertyName(string propertyName)
        {
            // Verify that the property name matches a real,  
            // public, instance property on this object.
            if (TypeDescriptor.GetProperties(this)[propertyName] == null)
            {
                string msg = "Invalid property name: " + propertyName;

                if (this.ThrowOnInvalidPropertyName)
                    throw new Exception(msg);
                else
                    Debug.Fail(msg);
            }
        }

        /// <summary>
        /// Returns whether an exception is thrown, or if a Debug.Fail() is used
        /// when an invalid property name is passed to the VerifyPropertyName method.
        /// The default value is false, but subclasses used by unit tests might 
        /// override this property's getter to return true.
        /// </summary>
        protected virtual bool ThrowOnInvalidPropertyName { get; private set; }

        /// <summary>
        /// Gets a value indicating whether the control is in design mode
        /// (running in Blend or Visual Studio).
        /// </summary>
        
        public static bool IsInDesignModeStatic
        {
            get
            {
                if (!_isInDesignMode.HasValue)
                {
#if SILVERLIGHT
                    _isInDesignMode = DesignerProperties.IsInDesignTool;
#else
                    var prop = DesignerProperties.IsInDesignModeProperty;
                    _isInDesignMode
                        = (bool)DependencyPropertyDescriptor
                        .FromProperty(prop, typeof(FrameworkElement))
                        .Metadata.DefaultValue;

                    // Just to be sure
                    if (!_isInDesignMode.Value
                        && Process.GetCurrentProcess().ProcessName.StartsWith("devenv", StringComparison.Ordinal))
                    {
                        _isInDesignMode = true;
                    }
#endif
                }

                return _isInDesignMode.Value;
            }
        }

        /// <summary>
        /// Gets a value indicating whether the control is in design mode
        /// (running under Blend or Visual Studio).
        /// </summary>
       
        public bool IsInDesignMode
        {
            get
            {
                return IsInDesignModeStatic;
            }
        }


        #endregion // Debugging Aides

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Raised when a property on this object has a new value.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Raises this object's PropertyChanged event.
        /// </summary>
        /// <param name="propertyName">The property that has a new value.</param>
        protected virtual void OnPropertyChanged(string propertyName)
        {
            this.VerifyPropertyName(propertyName);

            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }

        #endregion // INotifyPropertyChanged Members

        public event EventHandler RequestClose;
        protected void OnRequestClose()
        {
            EventHandler handler = this.RequestClose;
            if (handler != null)
                handler(this, EventArgs.Empty);
        }

        protected void RaiseFileSaved(String filename)
        {
            if (FileSaved != null)
            {
                foreach (Delegate d in FileSaved.GetInvocationList())
                {
                    d.DynamicInvoke(filename);
                }
                //FileSaved.DynamicInvoke
                //FileSaved(filename);
            }
        }

        protected void RaiseItemRead() {

            if (ItemRead != null)
            {
                foreach (Delegate d in ItemRead.GetInvocationList())
                {
                    d.DynamicInvoke(this,null);
                }
            }
        }

        protected void RaiseItemOperationStarted(int num, string action)
        {
            //if (ItemOperationStarted != null)
            //    ItemOperationStarted(num,action);

            if (ItemOperationStarted != null)
            {
                foreach (Delegate d in ItemOperationStarted.GetInvocationList())
                {
                    d.DynamicInvoke(num, action);
                }
            }
        }

        protected void RaiseItemOperationFinished()
        {
            if (ItemOperationFinished != null)
            {
                foreach (Delegate d in ItemOperationFinished.GetInvocationList())
                {
                    d.DynamicInvoke(new object[]{null,null});
                }
            }
        }

        #region IDisposable Members

        /// <summary>
        /// Invoked when this object is being removed from the application
        /// and will be subject to garbage collection.
        /// </summary>
        public void Dispose()
        {
            this.OnDispose();
        }

        /// <summary>
        /// Child classes can override this method to perform 
        /// clean-up logic, such as removing event handlers.
        /// </summary>
        protected virtual void OnDispose()
        {
        }

#if DEBUG
        /// <summary>
        /// Useful for ensuring that ViewModel objects are properly garbage collected.
        /// </summary>
        ~ViewModelBase()
        {
            string msg = string.Format("{0} ({1}) ({2}) Finalized", this.GetType().Name, this.DisplayName, this.GetHashCode());
            System.Diagnostics.Debug.WriteLine(msg);
        }

       
#endif

        #endregion // IDisposable Members
    }
}